package com.xyy.saas.payment.callback.core.handler;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.xyy.ec.order.api.refund.RefundApi;
import com.xyy.ec.order.dto.refund.OrderRefundDto;
import com.xyy.saas.payment.adpater.jdCredit.req.JDNotifyReq;
import com.xyy.saas.payment.adpater.jdCredit.req.JDRefundNotifyReq;
import com.xyy.saas.payment.callback.core.dto.CallbackMsg;
import com.xyy.saas.payment.callback.core.result.CallbackRunner;
import com.xyy.saas.payment.common.exception.PayBizException;
import com.xyy.saas.payment.common.pool.NamedTask;
import com.xyy.saas.payment.common.pool.PoolUtil;
import com.xyy.saas.payment.converter.PayCommonConverter;
import com.xyy.saas.payment.converter.RefundConverter;
import com.xyy.saas.payment.cores.vo.CallbackResultVo;
import com.xyy.saas.payment.dao.mapper.PayResultOrderMapper;
import com.xyy.saas.payment.dao.mapper.RefundOrderMapper;
import com.xyy.saas.payment.dao.model.OrderTransDataPo;
import com.xyy.saas.payment.dao.model.PayResultOrder;
import com.xyy.saas.payment.dao.model.RefundOrder;
import com.xyy.saas.payment.enums.JDNotifyStatusEnum;
import com.xyy.saas.payment.manager.PayManager;
import com.xyy.saas.payment.payment.core.bo.RefundBO;
import com.xyy.saas.payment.payment.core.service.PaymentService;
import com.xyy.saas.payment.trace.AlarmService;
import com.xyy.saas.payment.util.AssertUtil;
import com.xyy.saas.payment.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author liujf
 */
@Component
@Slf4j
public class JDRefundCallbackHandler extends JDCallbackHandler<JDRefundNotifyReq> {

    @Resource
    private PaymentService paymentService;

    @Resource
    private RefundOrderMapper refundOrderMapper;

    @Resource
    private CallbackRunner callbackRunner;

    @Resource
    private PayResultOrderMapper payResultOrderMapper;
    @Resource
    private AlarmService alarmService;
    @Reference(version = "1.0.0")
    private RefundApi refundApi;
    @Resource
    private PayManager payManager;

    @Override
    public String getMethod() {
        return "refundNotice";
    }

    @Override
    public JDNotifyReq parseRequest(String content) {
        return JSON.parseObject(content, JDRefundNotifyReq.class);
    }

    @Override
    public String createLockKey(String bizNo) {
        return RedisUtil.JD_CREDIT_REFUND_NOTIFY + bizNo;
    }


    @Override
    public void doHandle(JDRefundNotifyReq request) {
        //更新退款状态
        String refundStatus = request.getRefundStatus();
        String bizNo = request.getBizNo();
        // 查询退款信息
        RefundOrder refundOrder = refundOrderMapper.selectByRefundNo(bizNo);
        PayResultOrder payResultOrder = payResultOrderMapper.selectByPayNoAndChannel(refundOrder.getPayNo(), refundOrder.getChannel());
        log.info("JDRefundCallbackHandler#doHandle req:{},order:{}", JSON.toJSONString(request), JSON.toJSON(refundOrder));

        //幂等
        if ((JDNotifyStatusEnum.SUCCESS.getCode().equals(refundStatus) && RefundOrder.STATUS_FINISH.equals(refundOrder.getStatus())) ||
                JDNotifyStatusEnum.FAIL.getCode().equals(refundStatus) && RefundOrder.STATUS_FAIL.equals(refundOrder.getStatus())) {
            log.warn("JDRefundCallbackHandler#doHandle idempotent,refundStatus:{},status:{}", refundStatus, refundOrder.getStatus());
            return;
        }

        if (JDNotifyStatusEnum.SUCCESS.getCode().equals(refundStatus)) {
            RefundBO refundBO = RefundConverter.reqToSuccessBo(request);
            paymentService.updateRefundStatus(bizNo, refundBO, refundOrder);
            Long unixTime = refundBO.getDate().getTime() / 1000;

            // 退款成功的后续处理
            afterRefundSuccess(refundOrder);

            //推送mq业务消息
            callback(bizNo, CallbackResultVo.TYPE_REFUND_SUCCESS, refundOrder.getAmount(), unixTime, refundOrder.getCallbackAddress(), payResultOrder.getMerchantId(), refundOrder.getBusinessRefundNo(), null);
        } else if (JDNotifyStatusEnum.FAIL.getCode().equals(refundStatus)) {
            // 不能先成功在失败
            AssertUtil.isFalse(RefundOrder.STATUS_FINISH.equals(refundOrder.getStatus()), bizNo + "已经成功，不能失败");
            RefundBO refundBO = RefundConverter.reqToFailBo(request);
            paymentService.updateRefundStatus(bizNo, refundBO, refundOrder);

            //推送mq业务消息
            String failMsg = request.getResDesc();
            callback(bizNo, CallbackResultVo.TYPE_REFUND_FAIL, refundOrder.getAmount(), 0L, refundOrder.getCallbackAddress(), payResultOrder.getMerchantId(), refundOrder.getBusinessRefundNo(), failMsg);
//            alarmService.asyncAlarm("京东退款回调", "doHandle", "退款失败:" + failMsg, "refundNo:" + bizNo);
        } else {
            alarmService.asyncAlarm("京东退款回调", "doHandle", "暂不支持的退款状态", "refundNo:" + bizNo);
            throw new PayBizException("暂不支持的退款状态");
        }
    }

    private void afterRefundSuccess(RefundOrder refundOrder) {
        // 新增退款交易记录
        PoolUtil.ALARM_POOL.execute(NamedTask.createRun(()->{
            try {
                // 查询正向订单数据
                OrderTransDataPo transDataPo = payManager.queryOrderTransData(refundOrder.getPayNo());
                OrderRefundDto orderRefundDto = refundApi.queryRefundOrderByRefundOrderNo(refundOrder.getBusinessRefundNo());
                // 组装数据
                OrderTransDataPo refundTransDataPo = PayCommonConverter.buildRefundTransDataPo(transDataPo, orderRefundDto);
                // 持久化
                payManager.insertOrderTransData(refundTransDataPo);
            } catch (Exception e) {
                log.error("JDRefundCallbackHandler#afterRefundSuccess error:{}", refundOrder.getRefundNo(), e);
                alarmService.asyncAlarm("jd退款单新增交易数据异常", JSON.toJSONString(refundOrder));
            }
        },"jd退款单新增交易数据任务"));

    }

    private void callback(String tradeNo, String type, Integer amount, Long successTime, String callback, String merchantId, String businessOrderNo, String msg) {
        CallbackMsg callbackMsg = new CallbackMsg(tradeNo, type, amount, 0, successTime, callback, null, msg, null, businessOrderNo, merchantId);
        int retry = 0;
        while (retry < 3) {
            try {
                callbackRunner.callback(callbackMsg);
                break;
            } catch (Exception e) {
                log.error("JDRefundCallbackHandler.callback error:{}", e.getMessage(), e);
                retry++;
                try {
                    // 考虑接口耗时
                    Thread.sleep(retry * 100);
                } catch (InterruptedException ignore) {
                }
            }
        }
        if (retry >= 3) {
            alarmService.asyncAlarm("京东退款回调", "doHandle", "callback失败急急急！！！", "param:" + JSON.toJSONString(callbackMsg));
        }
    }
}
